#ifndef __SmGame_h__
#define __SmGame_h__

#include <iostream>

#include "GlGameListener.h"
#include "GlSize.h"
#include "GlPosition.h"
#include "GlSprite.h"

#include "GlSection.h"
#include "GlCamera.h"

#include "Elements.h"
#include "GlText.h"

namespace GraphicLibrary
{
	class Effect;
}

namespace SneakingMission
{
	class GameState;
	
	class Game
		: public GraphicLibrary::GameListener
	{
		public:
			Game();
			virtual ~Game();
			virtual void init();
			virtual bool tick(const float deltaTime);
			virtual void mouseDown(const float x, const float y);
			virtual void mouseUp(const float x, const float y);
			virtual void mouseMove(const float x, const float y);
			virtual void keyPressed(const unsigned int key);

			void setLastMap(std::string map);
			std::string getLastMap();

			inline static Game* GetSingleton()
			{
				if(!msSingleton)
					msSingleton = new Game();
				return msSingleton;
			}
		private:
			static Game*	msSingleton;
			GameState* mState;

		protected:
			GraphicLibrary::Sprite *testSprite;
			GraphicLibrary::Sprite *testSprite2;

			friend class GameState;
			void ChangeState(GameState* state);
	};

	class GameState
	{
		public:
			GameState();
			virtual ~GameState();
			virtual void init(Game* game)=0;
			virtual void uninit(Game* game)=0;
			virtual bool initialized()=0;
			virtual bool tick(Game* game, const float deltaTime)=0;
			virtual void mouseDown(Game* game, const float x, const float y)=0;
			virtual void mouseUp(Game* game, const float x, const float y)=0;
			virtual void mouseMove(Game* game, const float x, const float y)=0;
			virtual void keyPressed(Game* game, const unsigned int key)=0;
		protected:
			void ChangeState(Game* game, GameState* state);
	};

	const int TEXTBOX_LINE_COUNT = 9;
	const int MAPLIST_MAX_SIZE = 100;
	class Menu
		: public GameState
	{
		public:
			Menu();
			virtual ~Menu();
			virtual void init(Game* game);
			virtual void uninit(Game* game);
			virtual bool initialized();
			virtual bool tick(Game* game,const float deltaTime);
			virtual void mouseDown(Game* game,const float x, const float y);
			virtual void mouseUp(Game* game,const float x, const float y);
			virtual void mouseMove(Game* game,const float x, const float y);
			virtual void keyPressed(Game* game,const unsigned int key);

			inline static Menu* GetSingleton()
			{
				if(!msSingleton)
					msSingleton = new Menu();
				return msSingleton;
			}

		private:
			static Menu*	msSingleton;
			bool mTerminated;
			/* Levels:
			  0 - Main menu
			  1 - Game menu
			  2 - Highscores
			  3 - New Game menu (with maplist) */
			int mLevel;
			bool mInitialized;
			int mMapListPage;
			int mMapListNum;
			int mHighScoreListPage;
			int mHighScoreListNum;

			inline void terminate()
			{
				mTerminated = true;
			}

			void SetLevel(int level);
			void FreeSprites();
			void CreateSprites();

			void LoadMapList();
			void ClearMaps();
			bool LoadMaps();
			void SetMaps();
			void LoadHighScoreList();
			void ClearHighScores();
			bool LoadHighScores();
			void SetHighScores();
			std::string LoadHighScoreFromMap(std::string mapPath, int mapScore);

		protected:
			GraphicLibrary::Sprite *mGameButton;
			GraphicLibrary::Sprite *mHighScoresButton;
			GraphicLibrary::Sprite *mNewGameButton;
			GraphicLibrary::Sprite *mContinueButton;
			GraphicLibrary::Sprite *mBackButton;
			GraphicLibrary::Sprite *mExitButton;
			GraphicLibrary::Sprite *mTitle;
			GraphicLibrary::Sprite *mTextbox;
			GraphicLibrary::Sprite *mBackGround;
			GraphicLibrary::Sprite *mPrevButton;
			GraphicLibrary::Sprite *mNextButton;
			GraphicLibrary::Text *mTexts[TEXTBOX_LINE_COUNT];
			std::string mMapNames[MAPLIST_MAX_SIZE];
			std::string mMapPaths[MAPLIST_MAX_SIZE];
			std::string mMapScores[MAPLIST_MAX_SIZE];
	};

	const int PLAYER_LIFE = 3;
	const float COLLISION_WIDTH = 40.0f;
	const int MAX_SCORE = 999999999;
	class Map
		: public GameState
	{
	public:
		Map();
		virtual ~Map();
		virtual void init(Game* game);
		virtual void uninit(Game* game);
		virtual bool initialized();
		virtual bool tick(Game* game,const float deltaTime);
		virtual void mouseDown(Game* game,const float x, const float y);
		virtual void mouseUp(Game* game,const float x, const float y);
		virtual void mouseMove(Game* game,const float x, const float y);
		virtual void keyPressed(Game* game,const unsigned int key);
 
		inline static Map* GetSingleton()
		{
			if(!msSingleton)
				msSingleton = new Map();
			return msSingleton;
		}

	private:
		static Map*	msSingleton;
		bool mInitialized;
		Player player;
		std::vector<Wall> walls;
		std::vector<Enemy> enemies;
		std::vector<SlowField> slows;
		std::vector<Key> keys;
		std::vector<std::string> acquiredKeys;
		GraphicLibrary::Position goal;	
		int mPlayTime;
		int mLastPlayTime;
		int mPlayStartTime;
		int mHighScore;
		int acquiredKeyNum;
		std::string mMapPath;

		bool isMouseDown;
		bool enemyCollision();
		bool wallCollision();
		bool canPlayerMove();
		bool playerHitEnemy();
		bool playerReachedEnd();
		void RefreshStateText(bool isAlways);
		bool SaveHighScoreIfNeeded();
		void LoadHighScore();
		void SaveHighScore();
		void refreshPlayerSpeed();
		void refreshPlayerKeys();

		void destroyEffect();
		void manageEffect(const float deltaTime);
		void applyEffect(GraphicLibrary::Effect *effect);
	protected:
		GraphicLibrary::Sprite *mTestSprite;
		GraphicLibrary::Sprite *sPlayer;
		GraphicLibrary::Sprite *mGround;
		GraphicLibrary::Sprite *mGoal;
		GraphicLibrary::Sprite *mStart;
		GraphicLibrary::Text *mMapName;
		GraphicLibrary::Text *mPlayTimeText;
		GraphicLibrary::Text *mLifeText;
		GraphicLibrary::Text *mKeyText;
		GraphicLibrary::Effect*	mCurrentEffect;
		std::vector<GraphicLibrary::Sprite*> mEmptyKeys;
	};

} //namespace SneakingMission

#endif // __SmGame_h__
